package com.yeyks.rocketmq.listener;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.openservices.ons.api.Action;
import com.aliyun.openservices.ons.api.ConsumeContext;
import com.aliyun.openservices.ons.api.Message;
import com.aliyun.openservices.ons.api.MessageListener;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists;
import com.yeyks.account.dal.dao.AccountSetoutMapper;
import com.yeyks.common.appcommon.result.CommonResult;
import com.yeyks.common.em.WebSocketTypeEnum;
import com.yeyks.common.pojo.WebSocketBaseSendPojo;
import com.yeyks.common.utils.apputil.mqenum.TemplateType;
import com.yeyks.common.utils.apputil.redis.RedisService;
import com.yeyks.common.utils.apputil.rediskey.RedisKey;
import com.yeyks.common.utils.apputil.type.GeTuiType;
import com.yeyks.commonReference.append.rocketmq.pojo.RocketMQWebsocketBasePojo;
import com.yeyks.dao.AppAccountInfoMapper;
import com.yeyks.entity.AppAccountInfo;
import com.yeyks.hotel.dal.dao.HotelInfoMapper;
import com.yeyks.hotel.dal.domain.HotelInfo;
import com.yeyks.order.dal.dao.OrderHeadMapper;
import com.yeyks.order.dal.domain.OrderHead;
import com.yeyks.service.impl.AppGeTuiService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.yeyks.common.utils.apputil.rediskey.RedisKey.MQ_ONE_CUSTOMER;


/**
 * 抢单结果（手动抢单，自动抢单，下单通知等）
 *
 * @author Administrator
 * @date 2019/08/09 16:06
 */
@Slf4j
@Component
public class MessageGrabOrderResultListener implements MessageListener {

    @Autowired
    private AppGeTuiService geTuiService;
    @Autowired
    private AccountSetoutMapper accountSetoutMapper;

    @Autowired
    private AppAccountInfoMapper accountInfoMapper;

    @Autowired
    private OrderHeadMapper orderHeadMapper;

    @Autowired
    private RedisService redisService;

    @Autowired
    private HotelInfoMapper hotelInfoMapper;

    @Override
    public Action consume(Message message, ConsumeContext consumeContext) {
        try {
            Long startTime = System.currentTimeMillis();
            byte[] body = message.getBody();
            //获取到接收的消息，由于接收到的是byte数组，所以需要转换成字符串
            String msg = new String(body);
            //处理业务逻辑
            disposeLogic(msg);
            log.info("抢单结果GrabOrderResult检测：监听到的消息：message = {}", msg);
            Long endTime = System.currentTimeMillis();
            log.info("抢单结果GrabOrderResult检测：单次消费耗时：" + (endTime - startTime) / 1000);
        } catch (Exception e) {
            log.error("MessageListener.consume error:" + e.getMessage(), e);
        }
        return Action.CommitMessage;
    }

    /**
     * @param msg 监听到的信息
     */
    private void disposeLogic(String msg) {
        try {
            RocketMQWebsocketBasePojo webSocket = JSONUtil.toBean(msg, RocketMQWebsocketBasePojo.class);
            if (null != webSocket) {
                log.info("抢单结果返回对象{}", webSocket);
                geTuiGrabStatusPush(webSocket);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("抢单结果GrabOrderResult检测：处理监听消息异常：msg = {}", msg);
        }
    }

    /**
     * 个推(抢单结果相关消息)
     *
     * @param webSocket 抢单结果消息
     */
    private void geTuiGrabStatusPush(RocketMQWebsocketBasePojo webSocket) {

        String orderNo = "";
        String title = "";
        String json = "";

        //抢单
        if (webSocket.getType().equals(WebSocketTypeEnum.ROB_ORDER_RESULT.value())) {
            Map resultMap = (Map) JSONUtil.parse(webSocket.getBody());
            if (!StringUtils.isEmpty(resultMap.get("failMsg"))) {
                title = (String) resultMap.get("failMsg");
                json = JSONObject.toJSON(new TemplateType<String>(CommonResult.HOTEL_GRAB_FAIL,
                        title,
                        webSocket.getBody()
                )).toString();
                //推送（个推）--》 只给某个酒店推送
                geTuiService.morePush(GeTuiType.GRAB_ORDER_RESULT, getCIds(webSocket.getUserId()), title,
                        json);
            } else if (!StringUtils.isEmpty(resultMap.get("successMsg"))) {
                orderNo = (String) resultMap.get("orderNo");
                title = (String) resultMap.get("successMsg");
                json = JSONObject.toJSON(new TemplateType<String>(CommonResult.HOTEL_GRAB_SUCCESS,
                        title,
                        orderNo
                )).toString();
                //推送（个推）--》 只给某个酒店推送
                geTuiService.morePush(GeTuiType.CREATE_ORDER, getCIds(webSocket.getUserId()), title,
                        json);
                //给上级推送信息，不包含自身 ,type 传 1
                pushGrabSuccessGeTui(orderNo, 1);
            }
        } else if (webSocket.getType().equals(WebSocketTypeEnum.ORDER.value())) {
            //自动抢单推送，和B2C的推送保持一致。
            WebSocketBaseSendPojo baseSendPojo = JSONObject.parseObject(webSocket.getBody(), WebSocketBaseSendPojo.class);
            if (baseSendPojo.getType().equals(WebSocketTypeEnum.ORDER.value())) {
                Map resultMap = (Map) JSONUtil.parse(baseSendPojo.getDataStr());
                orderNo = (String) resultMap.get("orderNo");
                //全量推送 ,type 传 2
                pushGrabSuccessGeTui(orderNo, 2);
            }

        }
        //下单通知
        else if (webSocket.getType().equals(WebSocketTypeEnum.B2C_ORDER_SUCCESS.value())) {
            pushOrderGeTui(webSocket.getOrderNo());
        }

    }


    /**
     * 只给酒店上级推送消息的方法
     *
     * @param orderNo 订单号
     * @param type    推送设备判断， 1 --> 只给上级推送。 2 --> 全量推送（B2C的逻辑推送）
     */
    private void pushGrabSuccessGeTui(String orderNo, Integer type) {
        OrderHead orderHead = orderHeadMapper.selectOne(new QueryWrapper<OrderHead>().eq(OrderHead.ORDER_NO, orderNo));
        if (orderHead.getVipFlag() == 1) {
            log.info("臻选订单，不进行推送！！");
            return;
        }
        int count = 0;
        String oneKey = MQ_ONE_CUSTOMER + ":" + orderHead.getOrderNo() + ":" + orderHead.getStatus();

        HotelInfo hotelInfo = hotelInfoMapper.selectByPrimaryKey(orderHead.getHotelId());

        //根据type ，得到相应的设备集合
        List<String> cIds = getOnlyParent(hotelInfo.getOperatorId(), type);

        String title = OrderHead.convertMessage(orderHead);
        //信息[用于IOS，Android获取信息]
        String json = JSONObject.toJSON(new TemplateType<String>(CommonResult.SUCCESS,
                title,
                orderHead.getOrderNo()
        )).toString();

        //只推送一次
        String value = redisService.get(oneKey);
        if (value != null && !"".equals(value)) {
            if (Integer.valueOf(value) == count) {
                log.info("请不要重复发送消息！");
            } else {
                //推送（个推）--》 同时给上级推送
                geTuiService.morePush(GeTuiType.CREATE_ORDER, cIds, title,
                        json);
            }
        } else {
            redisService.setAndExpire(oneKey, String.valueOf(count), RedisKey.KEEP_TIME, TimeUnit.MINUTES);
            geTuiService.morePush(GeTuiType.CREATE_ORDER, cIds, title,
                    json);
        }
    }

    /**
     * 下订单的推送信息
     *
     * @param orderNo 订单号
     */
    private void pushOrderGeTui(String orderNo) {

        try {
            OrderHead orderHead = orderHeadMapper.selectOne(new QueryWrapper<OrderHead>().eq(OrderHead.ORDER_NO, orderNo));

            int count = 0;
            String oneKey = MQ_ONE_CUSTOMER + ":" + orderHead.getOrderNo() + ":" + orderHead.getStatus();

            log.info("object" + orderHead + "用户ID" + orderHead.getUserId() +
                    "开始消费创建订单信息，调用 推送接口");

            HotelInfo hotelInfo = hotelInfoMapper.selectByPrimaryKey(orderHead.getHotelId());

            //判断订单类型，如果是臻选酒店的订单，不进行推送（优享订单也进行推送）
            if (orderHead.getVipFlag() == 1) {
                log.info("臻选订单，不进行推送！！");
                return;
            }

            //设备集合(如果是CN的订单下单，只给总公司及下面的子公司进行推送)
            List<String> cIds = null;
            if("cn".equals(orderHead.getSourceType())){
                cIds = getAdminCIds();
            } else{
                //cIds = getCIds(hotelInfo.getOperatorId());
                //全量推送
                cIds = getOnlyParent(hotelInfo.getOperatorId(), 2);
            }
            //标题[用于IOS标题]
            String title = OrderHead.convertMessage(orderHead);
            //信息[用于IOS，Android获取信息]
            String json = JSONObject.toJSON(new TemplateType<String>(CommonResult.SUCCESS,
                    title,
                    orderHead.getOrderNo()
            )).toString();

            //只推送一次(防止重复的推送)
            String value = redisService.get(oneKey);
            if (value != null && !"".equals(value)) {
                if (Integer.valueOf(value) == count) {
                    log.info("====================你正在重复消费消息================");
                } else {
                    //推送
                    geTuiService.morePush(GeTuiType.CREATE_ORDER, cIds, title, json);
                }
            } else {
                redisService.setAndExpire(oneKey, String.valueOf(count), RedisKey.KEEP_TIME, TimeUnit.MINUTES);
                geTuiService.morePush(GeTuiType.CREATE_ORDER, cIds, title, json);
            }
        } catch (Exception e) {
            log.info("解析推送对象失败");
            e.printStackTrace();
        }
    }


    /**
     * 得到推送的 设备Id集合
     *
     * @param operatorId 当前酒店的管理员Id
     * @return 返回设备Id集合
     */
    private List<String> getCIds(Integer operatorId) {

        //子账号的相关处理， 跟ManagerId相关
        List<String> targets = this.getAccountIds(operatorId);
        List<String> cIds = Lists.newArrayList();
        //根据账户Id查询设备Id集合
        if (!CollectionUtils.isEmpty(targets)) {
            cIds = accountSetoutMapper.selectByAccountIds(targets);
        }
        return cIds;
    }

    /**
     * 根据管理员ID得到子账号及自己的集合
     *
     * @param operatorId 当前酒店的管理员Id
     * @return 返回管理员集合
     */
    private List<String> getAccountIds(Integer operatorId) {
        List<String> targets = new ArrayList<>();
        AppAccountInfo accountInfo = accountInfoMapper.selectByPrimaryKey(operatorId);
        if (accountInfo.getManagerId() != null) {

            targets.add(accountInfo.getManagerId().toString());
        }
        //加上本身信息
        targets.add(operatorId.toString());

        return targets;
    }


    /**
     * 得到总公司及子公司的设备集合信息
     *
     * @return 返回设备Id集合
     */
    private List<String> getAdminCIds(){
        List<Integer> adminIds = accountInfoMapper.selectIdsAllParent(1403);
        List<String> cIds = Lists.newArrayList();
        //根据账户Id查询设备Id集合
        if (!CollectionUtils.isEmpty(adminIds)) {
            //integer集合 --> String 集合
            List<String> allAccountIds = adminIds.stream().map(str -> str.toString()).collect(Collectors.toList());
            cIds = accountSetoutMapper.selectByAccountIds(allAccountIds);
        }
        return cIds;
    }

    /**
     * 只获取上级的Id信息
     *
     * @param operatorId 当前酒店的管理员Id
     * @param type       推送设备判断， 1 --> 只给上级推送。 2 --> 全量推送（B2C的逻辑推送）
     * @return 返回设备Id集合
     */
    private List<String> getOnlyParent(Integer operatorId, Integer type) {

        //子账号的相关处理， 跟ManagerId相关
        Integer accountId = operatorId;
        AppAccountInfo accountInfo = accountInfoMapper.selectByPrimaryKey(accountId);
        if (accountInfo.getManagerId() != null) {
            accountId = accountInfo.getManagerId();
        }
        //定义账号的集合
        List<String> targets = new ArrayList<>();

        List<Integer> adminIds = accountInfoMapper.selectIdsAllParent(accountId);

        if (!CollectionUtils.isEmpty(adminIds)) {
            if (type == 1) {
                for (Integer id : adminIds) {
                    //排除当前管理员
                    if (id.equals(operatorId)) {
                        continue;
                    }
                    targets.add(id.toString());
                }
            } else {
                for (Integer id : adminIds) {
                    targets.add(id.toString());
                }
                targets.add(operatorId.toString());
            }
        }

        List<String> cIds = Lists.newArrayList();
        //根据账户Id查询设备Id集合
        if (!CollectionUtils.isEmpty(targets)) {
            cIds = accountSetoutMapper.selectByAccountIds(targets);
        }
        return cIds;
    }
}
